﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;

namespace StoneStorage
{
    public class BusinessRules
    {
        private StoneStorageDataSet dSet;

        public BusinessRules(StoneStorageDataSet dataSet)
        {
            if (dataSet == null)
            {
                throw new ArgumentNullException("dataSet");
            }
            dSet = dataSet;
        }

        /// <summary>
        /// Добавление приходной накладной
        /// </summary>
        public void AddIncomeInvoice(MyInvoice invoice)
        {
            this.CheckInvoice(invoice);

            if (dSet.IncomeInvoiceData.Any(s => (s.Number == invoice.Number) &&
                (s.Date == invoice.Date)))
            {
                throw new InvalidInvoiceException(
                    String.Format("Приходная накладная с номером {0} и датой {1} уже добавлена",
                    invoice.Number, invoice.Date), invoice);
            }

            var invoceDataRow = dSet.IncomeInvoiceData.AddIncomeInvoiceDataRow(
                invoice.Number,
                invoice.Date,
                invoice.Deliverer,
                invoice.Accepter);

            foreach (ItemForInvoice item in invoice.Items)
            {
                var storageRow = FindRowInTheStorage(item);

                if (storageRow == null)
                {
                    storageRow = dSet.Storage.AddStorageRow(
                        dSet.StoneDictionary.FindById((int)item.StoneId),
                        dSet.ProducerDictionary.FindById((int)item.ProducerId),
                        item.Length,
                        item.Width,
                        item.Height,
                        item.Count);
                }
                else
                {
                    storageRow.Count += item.Count;
                }

                dSet.IncomeInvoiceItem.AddIncomeInvoiceItemRow(
                    storageRow, item.Count, invoceDataRow);
            }
        }
        /// <summary>
        /// Ищет камень на складе
        /// </summary>
        /// <param name="item">item</param>
        /// <returns>Строка данных из таблицы Storage. Если камень не найден будет null</returns>
        public StoneStorageDataSet.StorageRow FindRowInTheStorage(ItemForInvoice item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            var storageRow = dSet.Storage.SingleOrDefault(s => ((int)item.StoneId == s.StoneId) &&
                ((int)item.ProducerId == s.ProducerId) &&
                (item.Length == s.StoneLength) &&
                (item.Width == s.StoneWidth) &&
                (item.Height == s.StoneHeight));

            return storageRow;
        }

        // Удаление приходной накладной

        public void RemoveIncomeInvoice(int number, DateTime date)
        {
            var incomeInvoiceDataRow = dSet.IncomeInvoiceData.SingleOrDefault(r =>
                (r.Number == number) && (r.Date == date));

            if (incomeInvoiceDataRow == null)
            {
                throw new InvalidInvoiceException("Попытка удалить несуществующую приходную накладную");
            }

            var incomeInvoiceItemRows = incomeInvoiceDataRow.GetIncomeInvoiceItemRows();

            foreach (var itemRow in incomeInvoiceItemRows)
            {
                var storageRow = itemRow.StorageRow;

                if ((storageRow.Count - itemRow.Count) < 0)
                {
                    throw new InvalidInvoiceException("Количество камней меньше нуля");
                }
            }

            foreach (var itemRow in incomeInvoiceItemRows)
            {
                var storageRow = itemRow.StorageRow;

                storageRow.Count -= itemRow.Count;
                itemRow.Delete();
            }

            incomeInvoiceDataRow.Delete();
        }

        // Добавление расходной накладной

        public void AddExpenditureInvoice(MyInvoice invoice)
        {
            CheckInvoice(invoice);

            if (dSet.ExpenditureInvoiceData.Any(s =>
                (s.Number == invoice.Number) && (s.Date == invoice.Date)))
            {
                throw new InvalidInvoiceException(
                    String.Format("Расходная накладная с номером {0} и датой {1} уже добавлена",
                    invoice.Number, invoice.Date), invoice);
            }

            CheckExpenditureInvoiceItem(invoice);

            var expInvoiceData = dSet.ExpenditureInvoiceData.AddExpenditureInvoiceDataRow(
                invoice.Number,
                invoice.Date,
                invoice.Deliverer,
                invoice.Accepter);

            foreach (var item in invoice.Items)
            {
                var storageRow = FindRowInTheStorage(item);

                storageRow.Count -= item.Count;

                var expInvoiceItem = dSet.ExpenditureInvoiceItem.AddExpenditureInvoiceItemRow(
                    storageRow,
                    item.Count,
                    expInvoiceData);
            }
        }

        // Удаление расходной накладной

        public void RemoveExpenditureInvoice(int number, DateTime date)
        {
            var expInvoiceRow = dSet.ExpenditureInvoiceData.SingleOrDefault(r =>
                (r.Number == number) &&
                (r.Date == date));
            if (expInvoiceRow == null)
            {
                throw new InvalidInvoiceException("Попытка удалить несуществующую расходную накладную");
            }
            var expInvoiceItemRow = expInvoiceRow.GetExpenditureInvoiceItemRows();

            foreach (var itemRow in expInvoiceItemRow)
            {
                var storageRow = itemRow.StorageRow;

                storageRow.Count += itemRow.Count;
                itemRow.Delete();
            }
            expInvoiceRow.Delete();
        }

        public void CheckExpenditureInvoiceItem(MyInvoice invoice)
        {
            if (invoice == null)
            {
                throw new ArgumentNullException("invoice");
            }

            foreach (var item in invoice.Items)
            {
                var storageRow = FindRowInTheStorage(item);

                if (storageRow == null)
                {
                    throw new InvalidInvoiceException(
                        "Попытка добавить в расходную накладную несуществующий камень", item);
                }

                if ((storageRow.Count - item.Count) < 0)
                {
                    throw new InvalidInvoiceException(
                        "Попытка израсходовать товара больше, чем есть на складе." + "\n" + "\n" +
                        "На складе: " + storageRow.Count + " шт.",
                        item);
                }
            }
        }

        // Проверка накладной

        public void CheckInvoice(MyInvoice invoice)
        {
            if (invoice == null)
            {
                throw new ArgumentNullException("invoice");
            }

            if (invoice.Items.Count == 0)
            {
                throw new InvalidOperationException("Нельзя добавить пустую накладную");
            }

            foreach (var item in invoice.Items)
            {
                if (item.StoneId == null)
                {
                    throw new InvalidInvoiceException("Не задан вид камня", item);
                }

                if (item.ProducerId == null)
                {
                    throw new InvalidInvoiceException("Не задан производитель", item);
                }

                if (item.Length <= 0)
                {
                    throw new InvalidInvoiceException("Длина должна быть больше нуля", item);
                }

                if (item.Width <= 0)
                {
                    throw new InvalidInvoiceException("Ширина должна быть больше нуля", item);
                }

                if (item.Height <= 0)
                {
                    throw new InvalidInvoiceException("Высота должна быть больше нуля", item);
                }

                if (item.Count <= 0)
                {
                    throw new InvalidInvoiceException("Количество должно быть больше нуля", item);
                }
            }
        }

        // Поиск последнего номера накладной за день

        public int CreateInvoiceNumber(DataColumn numberColumn, DataColumn dateColumn, DateTime date)
        {
            if (dateColumn == null)
            {
                throw new ArgumentNullException("dateColumn");
            }

            if (numberColumn == null)
            {
                throw new ArgumentNullException("numberColumn");
            }

            var table = dateColumn.Table;

            var res = table
                .AsEnumerable()
                .Where(row => row.Field<DateTime>(dateColumn).Date == date.Date);
            if (res.Any())
            {
                return res.Max(r => r.Field<int>(numberColumn)) + 1;
            }
            return 1;
        }

        /// <summary>
        /// Создание MyInvoice по выбранному из dgvChooseInvoice InvoiceData.
        /// </summary>
        /// <param name="row">Строка данных.</param>
        /// <param name="kind">Вид накладной</param>
        public MyInvoice CreateMyInvoice(DataRow row, InvoiceKindEnum kind)
        {
            if (row == null)
            {
                throw new ArgumentNullException("row");
            }

            if (!(kind == InvoiceKindEnum.Expenditure) && !(kind == InvoiceKindEnum.Income))
            {
                throw new InvalidOperationException("Не известен тип накладной");
            }

            MyInvoice myInvoice = new MyInvoice();

            if (kind == InvoiceKindEnum.Income)
            {
                var invoiceDataRow = (StoneStorageDataSet.IncomeInvoiceDataRow)row;

                myInvoice.Number = invoiceDataRow.Number;
                myInvoice.Date = invoiceDataRow.Date;
                myInvoice.Deliverer = invoiceDataRow.Deliverer;
                myInvoice.Accepter = invoiceDataRow.Accepter;

                var invoiceItemRows = invoiceDataRow.GetIncomeInvoiceItemRows();

                foreach (var item in invoiceItemRows)
                {
                    var storageRow = item.StorageRow;

                    ItemForInvoice myItem = new ItemForInvoice();
                    myItem.StoneId = storageRow.StoneId;
                    myItem.ProducerId = storageRow.ProducerId;
                    myItem.Length = storageRow.StoneLength;
                    myItem.Width = storageRow.StoneWidth;
                    myItem.Height = storageRow.StoneHeight;
                    myItem.Count = item.Count;

                    myInvoice.Items.Add(myItem);
                }
            }
            
            if (kind == InvoiceKindEnum.Expenditure)
            {
                var invoiceDataRow = (StoneStorageDataSet.ExpenditureInvoiceDataRow)row;

                myInvoice.Number = invoiceDataRow.Number;
                myInvoice.Date = invoiceDataRow.Date;
                myInvoice.Deliverer = invoiceDataRow.Deliverer;
                myInvoice.Accepter = invoiceDataRow.Accepter;

                var invoiceItemRows = invoiceDataRow.GetExpenditureInvoiceItemRows();

                foreach (var item in invoiceItemRows)
                {
                    var storageRow = item.StorageRow;

                    ItemForInvoice myItem = new ItemForInvoice();
                    myItem.StoneId = storageRow.StoneId;
                    myItem.ProducerId = storageRow.ProducerId;
                    myItem.Length = storageRow.StoneLength;
                    myItem.Width = storageRow.StoneWidth;
                    myItem.Height = storageRow.StoneHeight;
                    myItem.Count = item.Count;

                    myInvoice.Items.Add(myItem);
                }
            }
            return myInvoice;
        }

        public void FormattingCell(DataGridViewCellFormattingEventArgs e)
        {
            throw new NotImplementedException();
        }
    }
}

